package com.grape.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.grape.constants.Constants;
import com.grape.dto.OnlineUserDTO;
import com.grape.dto.SysUserDTO;
import com.grape.dto.UserDetailDTO;
import com.grape.enums.RedisKeyEnums;
import com.grape.error.BusinessException;
import com.grape.redis.service.IRedisService;
import com.grape.utils.*;
import com.grape.vo.BaseVo;
import com.grape.vo.*;
import com.grape.wrapper.BaseWrapper;
import com.grape.entity.SysPermission;
import com.grape.entity.SysRole;
import com.grape.entity.SysUser;
import com.grape.domain.SysUserRole;
import com.grape.mapper.SysUserMapper;
import com.grape.service.ISysPermissionService;
import com.grape.service.ISysRoleService;
import com.grape.service.ISysUserRoleService;
import com.grape.service.ISysUserService;
import lombok.AllArgsConstructor;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * 用户信息表 服务实现类
 *
 * @author  putao
 * @email   2628279194@qq.com
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

//    private final UserDetailsService userDetailsService;

    private final IRedisService redisService;

//    private final JwtUtil jwtUtil;

    private final ISysRoleService roleService;

    private final ISysPermissionService permissionService;

//    private final JwtProperty jwtProperty;

    private final SendCodeUtils sendCodeUtils;

    private final ISysUserRoleService userRoleService;

//    private final CommonProperty commonProperty;

//    private final IUserChannelStore userChannelStore;

//    private final IAccountBookService accountBookService;

    private static final Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class);

    /**
     * 分页
     * @param baseVo 统一分页对象
     * @return 用户信息表集合
     */
    @Override
    public List<SysUser> listData(BaseVo baseVo) {
        QueryWrapper<SysUser> wrapper = new BaseWrapper<SysUser>().init();
        wrapper.like(Strings.isNotBlank(baseVo.getSearch()), "name", baseVo.getSearch())
                .eq(StringUtils.isNotBlank(baseVo.getColumnName())
                        && StringUtils.isNotBlank(baseVo.getSelect()), baseVo.getColumnName(), baseVo.getSelect());
        orderByModifyTimeDesc(wrapper);
        return this.list(wrapper);
    }

    /**
     * 修改
     * @param sysUser 用户信息表对象
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void updateData(SysUser sysUser) {
        List<SysRole> roleList = sysUser.getRoleList();
        List<SysUserRole> userRoleList = new ArrayList<>();
        boolean isAdmin = false;
        for (SysRole sysRole : roleList) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setId(IdUtil.getSnowflake(31, 31).nextIdStr());
            sysUserRole.setUserId(sysUser.getId());
            sysUserRole.setRoleId(sysRole.getId());
            userRoleList.add(sysUserRole);
            // TODO
//            isAdmin = isAdmin || commonProperty.getAdminCode().equals(sysRole.getCode());
        }
        sysUser.setIsAdmin(isAdmin ? Constants.ONE_STR : Constants.ZERO_STR);
        this.baseUpdate(sysUser);
        userRoleService.remove(new QueryWrapper<SysUserRole>().eq(Constants.USER_ID, sysUser.getId()));
        userRoleService.saveBatch(userRoleList);
        redisService.deleteKey(RedisKeyEnums.USER_DETAIL.join(sysUser.getId()));
    }

    /**
     * 新增
     * @param sysUser   用户信息表对象
     * @return          用户信息表对象
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public SysUser insertData(SysUser sysUser) {
        return this.baseInsert(sysUser);
    }

    /**
     * 删除
     * @param ids       用户ids
     * @return          删除条数
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public int deleteData(String ids) {
        int deleteCount = this.baseDelete(ids);
        for (String userId : StringUtils.convertList(ids)) {
            redisService.deleteKey(RedisKeyEnums.USER_DETAIL.join(userId));
        }
        return deleteCount;
    }

    /**
     * 根据id查询详情
     * @param id    用户id
     * @return      用户信息表对象
     */
    @Override
    public SysUser detail(String id) {
        return this.getUserById(id, null);
    }

    /**
     * 根据用户id查询redis用户信息
     * @param userId        用户id
     * @return              用户信息
     */
    private SysUser getUserByUserIdFromRedis(String userId) {
        String userJson2 = redisService.get(RedisKeyEnums.USER_DETAIL.join(userId));
        if (StringUtils.isNotBlank(userJson2)) {
            return JSON.parseObject(userJson2, SysUser.class);
        }
        return null;
    }

    /**
     * 用户名密码登录
     * @param sysUserDto 用户数据
     * @return          用户vo对象
     */
    @Override
    public UserVO login(SysUserDTO sysUserDto) {
        // TODO
//        LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(sysUserDto.getUsername());
//        if (!new BCryptPasswordEncoder().matches(sysUserDto.getPassword(), loginUser.getPassword())) {
//            throw new BusinessException("用户名或者密码错误");
//        }
//        SysUser user = this.getUserById(loginUser.getId(), null);
//        return this.getUserVo(user, sysUserDto.getType());
        return null;
    }

    /**
     * 根据vo设置redis信息和vo角色和权限信息
     * @param userVo    用户vo对象
     */
    private void setRedisValueAndSetUserVoValue(UserVO userVo) {
        List<SysRole> sysRoleList = roleService.getRoleByUserId(userVo.getId());
        if (CollectionUtil.isNotEmpty(sysRoleList)) {
            userVo.setRoleList(sysRoleList.stream().map(SysRole::getCode).collect(Collectors.toList()));
        }
        List<SysPermission> permissionList = permissionService.selectByUserId(userVo.getId());
        if (CollectionUtil.isNotEmpty(permissionList)) {
            userVo.setPermissionList(permissionList.stream().map(SysPermission::getUrl).collect(Collectors.toList()));
        }
        // TODO
//        redisService.setAndTime(RedisKeyEnums.LOGIN_USER.join(userVo.getUuid()), JSON.toJSONString(userVo), (long) jwtProperty.getExpiration());
//        redisService.setAndTime(RedisKeyEnums.USER_ID_KEY_TOKEN_VALUE.join(userVo.getId()), JSON.toJSONString(userVo.getToken()), (long) jwtProperty.getExpiration());
    }


    /**
     * 根据用户构建登录后的用户对象
     * @param user 用户表用户数据
     * @param type 登录类型
     * @return 用户vo
     */
    private UserVO getUserVo(SysUser user, String type) {
        UserVO userVo = new UserVO();
        BeanUtils.copyProperties(user, userVo);
        userVo.setId(user.getId());
        userVo.setUsername(user.getUsername());
        // TODO
//        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
//        LoginUser loginUser = getLoginUserByUser(user, authorities, type);
//        userVo.setToken(loginUser.getToken());
//        userVo.setExpireTime(loginUser.getExpireTime());
//        userVo.setUuid(loginUser.getUuid());
//        userVo.setAuthorities(authorities);
//        this.setRedisValueAndSetUserVoValue(userVo);
        return userVo;
    }

    /**
     * 根据手机号码发送验证码
     * @param phone 手机号码
     * @return      验证码
     */
    @Override
    public String sendCode(String phone) {
        StringBuilder codeSB = new StringBuilder();
        Boolean result = sendCodeUtils.sendCode(phone, codeSB);
        logger.info("号码为{}，发送验证码结果是：{}", phone, result);
        return codeSB.toString();
    }

    /**
     * 根据手机号码查询用户信息，不存在抛出异常
     * @param phone         手机号码
     * @param errorMessage  异常信息
     * @return              用户对象
     */
    private SysUser getUserByPhone(String phone, String errorMessage) {
        SysUser user = this.getOne(new QueryWrapper<SysUser>().eq(Constants.PHONE, phone).eq(Constants.IS_LOGGED, Constants.ZERO_STR));
        if (user == null) {
            throw new BusinessException(StringUtils.isNotBlank(errorMessage) ? errorMessage : "用户不存在，请重新输入");
        }
        if (Constants.ZERO_STR.equals(user.getStatus())) {
            throw new BusinessException(StringUtils.isNotBlank(errorMessage) ? errorMessage : "账号已锁定，请联系管理员");
        }
        return user;
    }

    /**
     * 根据手机号码查询用户信息，不存在抛出异常
     * @param userId        用户id
     * @param errorMessage  异常信息
     * @return              用户对象
     */
    private SysUser getUserById(String userId, String errorMessage) {
        SysUser user = this.getOne(new BaseWrapper<SysUser>().init().eq(Constants.ID, userId).eq(Constants.IS_LOGGED, Constants.ZERO_STR));
        if (user == null) {
            throw new BusinessException(StringUtils.isNotBlank(errorMessage) ? errorMessage : "错误：用户不存在");
        }
        if (Constants.ZERO_STR.equals(user.getStatus())) {
            throw new BusinessException(StringUtils.isNotBlank(errorMessage) ? errorMessage : "账号已锁定，请联系管理员");
        }
        return user;
    }

    /**
     * 自定义分页
     * @param baseVo        分页参数对象
     * @return              分页后用户集合
     */
    @Override
    public List<SysUser> listCustom(BaseVo baseVo) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.like(Strings.isNotBlank(baseVo.getSearch()), "username", baseVo.getSearch())
                .apply(org.apache.commons.lang3.StringUtils.isNotBlank(baseVo.getSql()), baseVo.getSql())
                .orderByDesc(Constants.MODIFY_TIME);
        List<SysUser> userList = this.list(wrapper);
        if (CollectionUtil.isNotEmpty(userList)) {
            for (SysUser user : userList) {
                user.setPassword(null);
            }
            return userList;
        }
        return Collections.emptyList();
    }

    /**
     * 修改头像
     * @param file  文件
     * @return      上传文件后的地址
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public String updateAvatar(MultipartFile file) throws Exception {
//        String userId = ThreadLocalUtil.getUserId();
//        UploadUtils uploadUtils = UploadFactory.getUploadComponentByType();
//        String imageUrl = uploadUtils.upload(file);
//        SysUser user = this.getUserById(userId, "用户不存在");
//        user.setAvatar(imageUrl);
//        this.updateById(user);
//        return imageUrl;
        // TODO
        return null;
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {
        // TODO
//        String token = ThreadLocalUtil.get().getToken();
//        Date expiredDate = jwtUtil.getExpiredDateFromToken(token);
//        String uuid = jwtUtil.getUuid(token);
//        Long expiredTime = (expiredDate.getTime() - new Date().getTime()) / 1000;
//        redisService.set(RedisKeyEnums.BLACK_LIST.join(uuid), token, expiredTime, TimeUnit.SECONDS);
    }

    /**
     * 定时更新用户连续记账天数
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void increaseConsecutiveBkDay() {
        List<SysUser> userList = this.list(new BaseWrapper<SysUser>().eq(Constants.DEL_FLAG, Constants.ZERO_STR).eq(Constants.IS_LOGGED, Constants.ZERO_STR));
        if (CollectionUtil.isEmpty(userList)) {
            return;
        }
        this.updateBatchById(userList);
    }

    /**
     *  用户分页
     * @param baseVo    分页数据
     * @return          分页实体对象
     */
    @Override
    public PageInfo<SysUser> userListPage(BaseVo baseVo) {
        PageInfo<SysUser> pageInfo = this.pageListByDelFlag(baseVo);
        List<SysUser> userList = pageInfo.getList();
        List<String> userIdList = userList.stream().map(SysUser::getId).collect(Collectors.toList());
        Map<String, List<SysRole>> userIdKeySysRoleListValueMap = new HashMap<>();
        List<SysRole> roleList = roleService.getRoleByUserIdList(userIdList);
        if (CollectionUtil.isNotEmpty(roleList)) {
            userIdKeySysRoleListValueMap = roleList.stream().collect(Collectors.groupingBy(SysRole::getUserId));
        }
        for (SysUser sysUser : userList) {
            sysUser.setRoleList(userIdKeySysRoleListValueMap.get(sysUser.getId()));
        }
        return pageInfo;
    }

    /**
     * 自定义分页
     * @param baseVo    分页参数
     * @return          分页后用户集合
     */
    @Override
    public List<SysUser> listPageCustom(BaseVo baseVo) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.like(Strings.isNotBlank(baseVo.getSearch()), Constants.USERNAME, baseVo.getSearch())
                .apply(org.apache.commons.lang3.StringUtils.isNotBlank(baseVo.getSql()), baseVo.getSql())
                .ne(Constants.ID, ThreadLocalUtil.getUserId())
                .orderByDesc(Constants.MODIFY_TIME);
        List<SysUser> userList = this.list(wrapper);
        if (CollectionUtil.isNotEmpty(userList)) {
            return userList;
        }
        return Collections.emptyList();
    }

    /**
     * 根据用户id锁定用户
     * @param startVo 用户id
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void start(StartVO startVo) {
        SysUser user = this.getUserById(startVo.getUserId(), "找不到用户信息");
        UpdateWrapper<SysUser> userUpdateWrapper = new UpdateWrapper<SysUser>().eq(Constants.ID, user.getId()).set("status", Constants.ONE_STR);
        this.update(userUpdateWrapper);
    }

    /**
     * 根据用户id锁定用户
     * @param stopVo 用户id和原因数据
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void stop(StopVO stopVo) {
        SysUser user = this.getUserById(stopVo.getUserId(), null);
        UpdateWrapper<SysUser> userUpdateWrapper = new UpdateWrapper<SysUser>().eq(Constants.ID, user.getId()).set("status", Constants.ZERO_STR).set("stop_reason", stopVo.getStopReason());
        this.update(userUpdateWrapper);
    }

    /**
     * 注销账户
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void logged() {
        UserVO userVo = ThreadLocalUtil.get();
        SysUser sysUser = this.getUserById(userVo.getId(), null);
        if (Constants.ONE_STR.equals(sysUser.getIsLogged())) {
            throw new BusinessException("用户已注销，请勿重复提交");
        }
        sysUser.setIsLogged(Constants.ONE_STR);
        sysUser.setStatus(Constants.ONE_STR);
        this.updateData(sysUser);
    }

    /**
     * 更新记账天数
     * @param number    记账天数
     */
    @Override
    @Transactional(readOnly = false)
    public void updateBookkeepingNumber(int number) {
        SysUser user = this.getUserById(ThreadLocalUtil.getUserId(), null);
        user.setBookkeepingNumber(number);
        user.updateInit();
        this.baseUpdate(user);
    }


    /**
     * 查询当前在线的用户
     *
     * @return 用户集合
     */
    @Override
    public List<OnlineUserDTO> onlineUserList() {
//        List<OnlineUserChannelDTO> channelDTOList = userChannelStore.getOnlineUserChannelList();
//        if (CollectionUtil.isEmpty(channelDTOList)) {
//            return Collections.emptyList();
//        }
//        List<String> userIdList = channelDTOList.stream().map(OnlineUserChannelDTO::getUserId).collect(Collectors.toList());
//        List<SysUser> userList = this.list(new BaseWrapper<SysUser>().init().in(Constants.ID, userIdList));
        List<OnlineUserDTO> onlineUserDTOList = new ArrayList<>();
//        Map<String, SysUser> userMap = userList.stream().collect(Collectors.toMap(SysUser::getId, Function.identity(), (v1, v2) -> v1));
//        for (OnlineUserChannelDTO channelDTO : channelDTOList) {
//            SysUser user = userMap.get(channelDTO.getUserId());
//            OnlineUserDTO onlineUserDTO = OnlineUserDTO.builder().id(user.getId()).username(user.getUsername()).avatar(user.getAvatar())
//                    .phone(user.getPhone()).activeTime(channelDTO.getActiveTime()).lastResetTime(channelDTO.getLastResetTime()).type(channelDTO.getType()).build();
//            onlineUserDTOList.add(onlineUserDTO);
//        }
        return onlineUserDTOList;
    }

    /**
     * 获取当前用户信息
     * @return  用户信息
     */
    @Override
    public UserDetailDTO detailDTO() {
        SysUser user = this.getUserById(ThreadLocalUtil.getUserId(), null);
        return UserDetailDTO.builder().id(user.getId()).username(user.getUsername())
                .uniqueId(user.getUniqueId()).bookkeepingNumber(user.getBookkeepingNumber()).bookkeepingDay(user.getBookkeepingDay())
                .createTime(user.getCreateTime()).avatar(user.getAvatar()).build();
    }

    /**
     * 根据用户id集合查询用户信息
     * @param userIdList 用户id集合
     * @return 用户集合
     */
    @Override
    public List<SysUser> listAll(List<String> userIdList) {
        List<SysUser> userList = this.list(new BaseWrapper<SysUser>().init().eq(Constants.IS_LOGGED, Constants.ZERO_STR)
                .eq(Constants.STATUS, Constants.ONE_STR).in(CollectionUtil.isNotEmpty(userIdList), Constants.ID, userIdList));
        if (userList == null) {
            return Collections.emptyList();
        }
        return userList;
    }

    /**
     * 获取当前用户信息
     * @return  用户信息
     */
    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void updateUserMember() {
        SysUser user = this.getUserById(ThreadLocalUtil.getUserId(), null);
        user.setIsMember(Constants.ONE_STR);
        this.baseUpdate(user);
    }

    /**
     * 根据用户名查询用户
     * @param username 用户名
     * @return 用户信息
     */
    @Override
    public SysUser getByUsername(String username) {
        return this.getUser(Constants.USERNAME, username);
    }

    private SysUser getUser(String column, String value) {
        SysUser user = this.getOne(new BaseWrapper<SysUser>().init().eq(column, value));
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        user.setRoleList(roleService.getRoleByUserIdList(Collections.singletonList(user.getId())));
        return user;
    }

    /**
     * 根据手机号查询用户
     * @param phone 手机号
     * @return 用户信息
     */
    @Override
    public SysUser getByPhone(String phone) {
        return this.getUser(Constants.PHONE, phone);
    }

    /**
     * 根据用户id查询用户
     * @return 用户信息
     */
    @Override
    public SysUser getByUserId() {
        return this.getUserById(ThreadLocalUtil.getUserId(), null);
    }

    /**
     * 根据用户id查询用户权限
     * @return 用户权限
     */
    @Override
    public List<SysPermission> getPermissionByUserId() {
        return permissionService.selectByUserId(ThreadLocalUtil.getUserId());
    }
}
